Project_Banner
About

An Auto-Runner Mobile Game featuring a baby dragon who’s goal is to crash and bounce through a magical castle to steal treasure for his hoard!

Drop Off Dragon was fully developed and released during the 2-month internship program at Mass Digi in the Unity Game Engine using Plastic as source control. The core design principle of the project was to create a game that could be easily enjoyed by all ages and easily approached by families and young kids within the mobile game demographic.

My contributions to this project include level design, a player ghost playback system, a tweener pipeline for UI, discovering and resolving many critical bugs and quality assurance.
Project-Image
Unity
C#
Plastic SCM
Ghost Data System
I developed a data structure and pipeline to record the player playing through a level and to be able to visually play that information in various parts of the application and even in the editor itself.
Project_Banner
Project_Banner
Recording Optimization
It would be ridiculous to record several keypoints of data every single frame of gameplay, so the solution I implemented was to record data on a frame interval: every 4 fixed updates the game would record a set list of necessary information for proper playback.
Project_Banner
Project_Banner
Smoothed Playback
Playing this data back as is results in the movement appearing choppy, so to compensate, the ghost playback is eased to glide from recorded point to point for the same interval of time it was recorded for. Below is the playback function script, which supports playing data back on a fixed interval as well as unscaled time for editor and level hints.
Project_Banner
 
/// <summary>
/// Called every frame to play back a Ghost Data File to simulate player movement playback 
/// Used by The Hint, Dev and Player PB Ghosts
/// </summary>
/// <param name="ghostObject"> The Ghost Object to output read data to</param>
private IEnumerator PlaybackGhost(GhostData ghostObject)
{

    // Tell the Ghost Object it is being played & Set Active
    ghostObject.m_isBeingPlayed = true;
    ghostObject.gameObject.SetActive(true);

    while(ghostObject.m_frameEvents.Count > 1) // Skip the final value with 1 for easing index
    {

        //Set sprite & Scale each inverval 
        ghostObject.GetComponent<SpriteRenderer>().sprite = ghostObject.m_frameEvents[0].m_playerSprite;
        ghostObject.GetComponent<SpriteRenderer>().flipX = ghostObject.m_frameEvents[0].m_playerDirection == Vector2.left;

        //Set the position
        ghostObject.gameObject.transform.position = ghostObject.m_frameEvents[0].m_playerPosition;

        // Wait for the interval to pass!
        for(int i = 0; i < ghostObject.m_recordedFrameInveral; i++)
        {

            // Ease to the next point
            float stepTime = ((float)i / (float) ghostObject.m_recordedFrameInveral);
            float curveValue = m_tweenEasing.Evaluate(stepTime);
            Vector2 setPos = Vector2.Lerp(ghostObject.m_frameEvents[0].m_playerPosition, ghostObject.m_frameEvents[1].m_playerPosition, curveValue);

            if(m_doEasing)
            {
                // Ease properties 
                ghostObject.gameObject.transform.position = setPos;
            }

            // Wait for update depending on playback timescale
            if(ghostObject.m_playbackTimescaleImmune)
            {
                // Wait for a ratio of secconds realtime to the recorded interval to lerp 
                yield return new WaitForSecondsRealtime(ghostObject.m_frameEvents[0].m_timeIntervalElapsed / (float) ghostObject.m_recordedFrameInveral); 
            }
            else
            {
                yield return new WaitForFixedUpdate(); 
            }

        }
        
        //Remove first in array after use
        ghostObject.m_frameEvents.RemoveAt(0);
    }

    // End the playback if there are no more frames!
    ghostObject.m_isBeingPlayed = false;
    ghostObject.gameObject.SetActive(false);
    yield return null;

}
Level Design Do's and Don'ts
A visual level design bible we created as a baseline guide for designing levels in the game. We opted for making the guide as visual as possible, including measurements and video demonstration of the capabilities of the player to show ourselves and future designers standard practice in the project.